/*
 * 文件名：SystemFilter.java 版权：Copyright by will_awoke 描述： 修改人：will_awoke 修改时间：2014-5-29 跟踪单号： 修改单号：
 * 修改内容：
 */

package com.qbgs.interceptor;


import java.io.IOException;
import java.io.PrintWriter;
import java.util.LinkedList;
import java.util.List;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.qbgs.constant.GlobalConstant;
import com.qbgs.rbac.service.SystemService;
import com.qbgs.util.ContextBeanUtils;


/**
 * 操作拦截器 不需要被拦截的方法请统一使用*.as方式命名，另请参见web.xml配置
 * 
 * @author will_awoke
 * @version 2014-5-29
 * @see SystemFilter
 * @since
 */
public class SystemFilter implements Filter
{

    /**
     * 日志
     */
    private static final Logger LOG = Logger.getLogger(SystemFilter.class);

    /**
     * ajax session超时返回值
     */
    private static String AJAX_TIME_OUT = null;

    /**
     * ajax 请求无权限返回值
     */
    private static String AJAX_NO_LIMIT = null;

    // ps: ajax 请求异常返回值 （在每个ajax请求中分别处理）

    /**
     * 直接放行url集合 兼容性处理，推荐将需要放行的url的后缀设置为.as，而不是加入到此list中
     */
    private static List<String> passUrls = null;

    static
    {
        AJAX_TIME_OUT = "ajaxSessionTimeOut";
        AJAX_NO_LIMIT = "ajaxNoLimit";

        passUrls = new LinkedList<String>();
        passUrls.add("/login/needPassedUrl.do");
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse rsp, FilterChain chain)
        throws IOException, ServletException
    {
        HttpServletRequest httpReq = (HttpServletRequest)req;

        // 获得当前请求url
        String url = httpReq.getServletPath();

        // 如果当前url在放行url集合内 则直接放行
        if (!passUrls.contains(url))
        {
            HttpServletResponse httpRsp = (HttpServletResponse)rsp;

            // 当前根目录
            String contentPath = httpReq.getContextPath();

            // 获得请求类型
            String type = httpReq.getHeader("X-Requested-With");

            // 获取session中当前用户名
            String loginName = (String)httpReq.getSession().getAttribute(
                GlobalConstant.AUTH_SESSION_USERNAME_KEY);

            if (StringUtils.isEmpty(loginName))
            {
                LOG.debug("user session is timeout...");

                // ajax请求 session过期时 返回字符串
                if ("XMLHttpRequest".equalsIgnoreCase(type))
                {
                    PrintWriter printWriter = httpRsp.getWriter();
                    printWriter.print(AJAX_TIME_OUT);
                    printWriter.flush();
                    printWriter.close();
                }
                // 普通http请求 直接返回sessionTimeout页面
                else
                {
                    // 转发forward操作，不需要写 contextPath，如果是重定向redirect操作，推荐写包括 contextPath 在内的 url
                    httpRsp.sendRedirect(contentPath + "/error/sessionTimeOut.as");
                }
            }
            else
            {
                // 鉴权结果
                boolean authFlag = false;
                try
                {
                    // returning cached instance of singleton bean 'userService'
                    SystemService systemService = (SystemService)ContextBeanUtils.getBean("systemService");

                    // TODO 如果执着于性能问题，可以将用户的权限存入缓存，每次鉴权时，直接判断是否在缓存内。当然需要提供缓存刷新接口，
                    // 每次用户的权限变更时都需要刷新缓存，确保缓存中是用户最新的权限。

                    // 执行鉴权
                    authFlag = systemService.isUrlInUserLimit(loginName, url);
                }
                catch (Exception e)
                {
                    LOG.error("systemFilter occur exception：" + e.toString() + "："
                              + e.getMessage());
                }
                // 鉴权通过则放行 否则拦截
                if (authFlag)
                {
                    // 继续后续chain
                    chain.doFilter(req, rsp);
                }
                // 鉴权不通过
                else
                {
                    // ajax请求 无操作权限时 返回字符串
                    if ("XMLHttpRequest".equalsIgnoreCase(type))
                    {
                        PrintWriter printWriter = httpRsp.getWriter();
                        printWriter.print(AJAX_NO_LIMIT);
                        printWriter.flush();
                        printWriter.close();
                    }
                    // 普通Http请求 直接返回无权限页面
                    else
                    {
                        httpRsp.sendRedirect(contentPath + "/error/noLimit.as");
                    }
                }
            }
        }
        else
        {
            // 继续后续chain
            chain.doFilter(req, rsp);
        }
    }

    @Override
    public void destroy()
    {
        // dostroy
    }

    @Override
    public void init(FilterConfig config)
        throws ServletException
    {
        // init config here
    }

}
